package org.devio.takephoto.permission;

import ohos.aafwk.ability.Ability;
import ohos.bundle.IBundleManager;
import ohos.security.SystemPermission;
import org.devio.takephoto.ResourceTable;
import org.devio.takephoto.app.TakePhoto;
import org.devio.takephoto.model.InvokeParam;
import org.devio.takephoto.model.TContextWrap;
import org.devio.takephoto.uitl.*;

import java.lang.reflect.Method;
import java.util.ArrayList;

/**
 * Created by penn on 16/9/22.
 */
public class PermissionManager {
    private static final String TAG = PermissionManager.class.getSimpleName();

    public enum TPermission {
        STORAGE(SystemPermission.WRITE_USER_STORAGE), CAMERA(SystemPermission.CAMERA);
        String stringValue;

        TPermission(String stringValue) {
            this.stringValue = stringValue;
        }

        public String stringValue() {
            return stringValue;
        }
    }

    public enum TPermissionType {
        GRANTED("Authorized"), DENIED("Unauthorized"), WAIT("Waiting for authorization"), NOT_NEED("No authorization is required."), ONLY_CAMERA_DENIED("You do not have permission to take photos."), ONLY_STORAGE_DENIED("You do not have the permission to read or write the SD card.");
        String stringValue;

        TPermissionType(String stringValue) {
            this.stringValue = stringValue;
        }

        public String stringValue() {
            return stringValue;
        }
    }


    private final static String[] methodNames =
            {"onPickFromCapture", "onPickFromCaptureWithCrop", "onPickMultiple", "onPickMultipleWithCrop", "onPickFromDocuments",
                    "onPickFromDocumentsWithCrop", "onPickFromGallery", "onPickFromGalleryWithCrop", "onCrop"};

    public static TPermissionType checkPermission(TContextWrap contextWrap, Method method) {
        String methodName = method.getName();
        boolean contain = false;
        for (String name : methodNames) {
            if (TextUtils.equals(methodName, name)) {
                contain = true;
                break;
            }
        }
        if (!contain) {
            return TPermissionType.NOT_NEED;
        }

        boolean cameraGranted = true, storageGranted =
                contextWrap.getAbility().verifySelfPermission(TPermission.STORAGE.stringValue())
                        == IBundleManager.PERMISSION_GRANTED;

        if (TextUtils.equals(methodName, "onPickFromCapture") || TextUtils.equals(methodName, "onPickFromCaptureWithCrop")) {
            cameraGranted = contextWrap.getAbility().verifySelfPermission(TPermission.CAMERA.stringValue())
                    == IBundleManager.PERMISSION_GRANTED;
        }

        boolean granted = storageGranted && cameraGranted;
        if (!granted) {
            ArrayList<String> permissions = new ArrayList<>();
            if (!storageGranted) {
                permissions.add(TPermission.STORAGE.stringValue());
            }
            if (!cameraGranted) {
                permissions.add(TPermission.CAMERA.stringValue());
            }
            requestPermission(contextWrap, permissions.toArray(new String[permissions.size()]));
        }
        return granted ? TPermissionType.GRANTED : TPermissionType.WAIT;
    }

    public static void requestPermission(TContextWrap contextWrap, String[] permissions) {
        if (contextWrap.getFraction() != null) {
            contextWrap.getFraction().requestPermissionsFromUser(permissions, TConstant.PERMISSION_REQUEST_TAKE_PHOTO);
        } else {
            contextWrap.getAbility().requestPermissionsFromUser(permissions, TConstant.PERMISSION_REQUEST_TAKE_PHOTO);
        }
    }

    public static TPermissionType onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        if (requestCode == TConstant.PERMISSION_REQUEST_TAKE_PHOTO) {
            boolean cameraGranted = true, storageGranted = true;
            for (int i = 0, j = permissions.length; i < j; i++) {
                if (grantResults[i] != IBundleManager.PERMISSION_GRANTED) {
                    if (TextUtils.equals(TPermission.STORAGE.stringValue(), permissions[i])) {
                        storageGranted = false;
                    } else if (TextUtils.equals(TPermission.CAMERA.stringValue(), permissions[i])) {
                        cameraGranted = false;
                    }
                }
            }
            if (cameraGranted && storageGranted) {
                return TPermissionType.GRANTED;
            }
            if (!cameraGranted && storageGranted) {
                return TPermissionType.ONLY_CAMERA_DENIED;
            }
            if (!storageGranted && cameraGranted) {
                return TPermissionType.ONLY_STORAGE_DENIED;
            }
            if (!storageGranted && !cameraGranted) {
                return TPermissionType.DENIED;
            }
        }
        return TPermissionType.WAIT;
    }

    public static void handlePermissionsResult(Ability ability, TPermissionType type, InvokeParam invokeParam,
                                               TakePhoto.TakeResultListener listener) {
        String tip = null;
        switch (type) {
            case DENIED:
                listener.takeFail(null, tip = ResUtil.getString(ability, ResourceTable.String_tip_permission_camera_storage));
                break;
            case ONLY_CAMERA_DENIED:
                listener.takeFail(null, tip = ResUtil.getString(ability, ResourceTable.String_tip_permission_camera));
                break;
            case ONLY_STORAGE_DENIED:
                listener.takeFail(null, tip = ResUtil.getString(ability, ResourceTable.String_tip_permission_storage));
                break;
            case GRANTED:
                try {
                    invokeParam.getMethod().invoke(invokeParam.getProxy(), invokeParam.getArgs());
                } catch (Exception e) {
                    e.printStackTrace();
                    listener.takeFail(null, tip = ResUtil.getString(ability, ResourceTable.String_tip_permission_camera_storage));
                }
                break;
            default:
                break;
        }
        if (tip != null) {
            UiUtil.showToast(ability, tip);
        }
    }
}
